﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace Legend.Fakes.Tests
{
    [TestFixture]
    public class ArgumentListTests
    {
        [Test]
        public void Constructor_is_properly_guarded()
        {
            IsProperlyGuardedConstraint.IsProperlyGuarded(() =>
                new ArgumentList(new object[] { "foo", 1 }, new[] {"foo", "bar" }));
        }

        [Test]
        public void Constructor_that_takes_method_is_properly()
        {
            var method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) });
            IsProperlyGuardedConstraint.IsProperlyGuarded(() =>
                new ArgumentList(new object[] { "foo", 1 }, method));
        }

        [Test]
        public void Constructor_that_takes_method_should_set_argument_names()
        {
            var method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) });

            var arguments = new ArgumentList(new object[] { "foo", "bar" }, method);

            Assert.That(arguments.ArgumentNames.SequenceEqual(new string[] { "argument", "argument2" }));
        }

        [Test]
        public void Constructor_should_throw_when_number_of_arguments_does_not_match_number_of_argument_names()
        {
            Assert.Throws<ArgumentException>(() => 
                new ArgumentList(new object[] { 1, 2 }, new[] { "first", "second", "third" }));
        }

        [Test]
        public void Get_called_with_index_should_return_argument_typed()
        {
            var arguments = CreateFakeArgumentList("foo", "bar");

            Assert.That(arguments.Get<string>(1), Is.EqualTo("bar"));
        }

        [Test]
        public void Get_called_with_name_should_return_argument_at_position_of_name()
        {
            var arguments = CreateFakeArgumentList(new[] { "foo", "bar" }, 1, 2);

            Assert.That(arguments.Get<int>("foo"), Is.EqualTo(1));
        }

        [Test]
        public void Get_called_with_argument_name_that_does_not_exist_throws_exception()
        {
            var arguments = CreateFakeArgumentList(new[] { "foo", "bar" }, 1, 2);

            Assert.Throws<ArgumentException>(() =>
                arguments.Get<int>("unknown"));
        }

        private ArgumentList CreateFakeArgumentList(string[] argumentNames, params object[] arguments)
        {
            return new ArgumentList(arguments, argumentNames);
        }

        private ArgumentList CreateFakeArgumentList(params object[] arguments)
        {
            return CreateFakeArgumentList(
                Enumerable.Range(0, arguments.Length).Select(x => x.ToString()).ToArray(),
                arguments);
        }
    }
}
